#include "SnakePlayer.h"
#include "MyMap.h"
#include <assert.h>

#define EAT_EVERYTHING 1

int SnakePlayer::eatNothing=0;
int SnakePlayer::eatenApple=1;
int SnakePlayer::eatenAnotherSnake=2;
int SnakePlayer::eatenMine=3;
int SnakePlayer::endedPlay=4;

void SnakePlayer::reset()
{
	MyMap * map=MyMap::instanceOf();
	SnakeSegment * headS= new SnakeSegment(startup_x,startup_y);
	segments.clear();
	segments.push_front(headS);

	this->setGameOver(false);
}

SnakePlayer::SnakePlayer(int number)
{
	startup_x = 0;
	startup_y = 0;
	
	this->number=number;
	/*ask map for head coordinates */
	MyMap * map=MyMap::instanceOf();
	SnakeSegment * headS=map->generateFieldForSnake();
	startup_x = headS->x;
	startup_y = headS->y;
	
	segments.push_front(headS);

	this->gameOver=false;
	/* auto register player in map*/
	map->registerSnakePlayer(this);
	this->lastDir=SNAKE_UP;

	/* normal condition - REAL player, set virtual to false*/
	setVirtualPlayerState(false);
	//printf("Snake head generated at s %d,%d \n",headS->x,headS->y);

}

SnakePlayer::SnakePlayer(
			 int number,
			 int virtualSnakeFirstX,
			 int virtualSnakeFirstY)
{

	MyMap * map=MyMap::instanceOf();

	/* assure there is no snake by this number so far*/
	SnakePlayer * snakeToFindByNumber= NULL;
	snakeToFindByNumber = map->getSnakePlayerByNumber(number);
	assert(NULL == snakeToFindByNumber);

	/* if there is not player by this number - can perform initialization */

	this->number=number;
	/*ask map for head coordinates */

	SnakeSegment * headS = new SnakeSegment( virtualSnakeFirstX, virtualSnakeFirstY);
	startup_x = headS->x;
	startup_y = headS->y;
	segments.push_front(headS);

	this->gameOver=false;
	/* auto register player in map*/
	map->registerSnakePlayer(this);
	this->lastDir=SNAKE_UP;

	/* Virtual ( remote) player, set virtual to true*/
	setVirtualPlayerState( true);

}

SnakePlayer::~SnakePlayer(void)
{

}

void SnakePlayer::eatApple(int oldendX, int oldendY)
{

	SnakeSegment * createdEnd=new SnakeSegment(oldendX,oldendY);
	segments.push_back(createdEnd);

#if  EAT_EVERYTHING == 0
	MyMap * map=MyMap::instanceOf();
	map->generateNextAppleOnMap();
#endif

}

void SnakePlayer::drawMeOnMap()
{
	MyMap * map=MyMap::instanceOf();
	if (gameOver)
	{

		return;
	}

	list<SnakeSegment *>::iterator it;
	it=segments.begin();

	while (it != segments.end())
	{
		map->setMapCharAt(C_PLAYER(number),(*it)->x,(*it)->y);

		++it;
	}//end of iterating segments


}

void SnakePlayer::updateDirections()
{

	list<SnakeSegment *>::reverse_iterator it;
	it=segments.rbegin();

	while (it != segments.rend())
	{

		++it;
	}//end of iterating segments


}

int SnakePlayer::moveTo(Direction d)
{
	//printf("SNAKE#%d ",this->number);
	if (gameOver)
	{
		//printf("Ended game previously - doing nothing.....\n");
		return SnakePlayer::endedPlay;
	}

	lastDir=d;
	MyMap * map=MyMap::instanceOf();
	SnakeSegment *hs=getHeadSegment();
	int x=hs->x;
	int y=hs->y;
	SnakeSegment next=map->getSegmentAtDirection(d, x, y);

	/* FIRST WE NEED TO CHECK ALL SNAKES SEGMENTS BEFORE WE MOVE ON
	 (to not check head of our snake on its current pos - result always true*/
	if (map->checkBelongsToSnakes(next.x, next.y) )
	{
		//printf("Eaten another snake - game over!!!\n");
		/* check another snakes segments*/
		/* if true that means, that we have eaten other snake or ourselvese*/
		/* game over*/
		this->gameOver=true;
		return SnakePlayer::eatenAnotherSnake;
	}

	/* moving snake into ....*/
	list<SnakeSegment *>::reverse_iterator it;
	it=segments.rbegin();
	SnakeSegment * endSnake=(*it);
	int endX=endSnake->x;
	int endY=endSnake->y;

	SnakeSegment * temp=NULL;

	while (it != segments.rend())
	{
		if (temp != NULL)
		{
			temp->x=(*it)->x;
			temp->y=(*it)->y;
		}
		temp=*(it);
		++it;
	}//end of iterating segments
	//now head
	//printf("NEW HEAD COORD(%d,%d)\n",next.x,next.y);
	(getHeadSegment())->x=next.x;
	(getHeadSegment())->y=next.y;

#if EAT_EVERYTHING
	eatApple(endX, endY);//increment snake func
#else
	if(map->isAppleAt(next.x,next.y))
	{
		//make snake bigger
		//printf("Eaten apple!!!!!!\n");
		eatApple(endX,endY);//increment snake func
	}

#endif

	if ( true == map->isMineAt(next.x, next.y) )
	{
		/* eaten mine -game over*/
		//printf("Eaten mine - game over!!!\n");

		this->gameOver=true;
		return SnakePlayer::eatenMine;

	}

	/*if here that means eatenNothing */

#if 0
	if(map->isEmptyAt(next.x,next.y))
	{
		//printf("Eat nothing....map is empty at(%d,%d)",x,y);
	}
#endif
	/* */

	updateDirections();

	map->debugMap();
	return SnakePlayer::eatNothing;
}

SnakeSegment * SnakePlayer::getHeadSegment()
{
	list<SnakeSegment *>::iterator it;

	it=segments.begin();

	assert(*it);
	return *it;

}

bool SnakePlayer::isThatMySegment(int x, int y)
{
	list<SnakeSegment *>::iterator it;
	it=segments.begin();

	while (it != segments.end())
	{
		if ((*it)->x == x && (*it)->y==y)
		{
			return true;
		}
		++it;
	}//end of iterating segments

	return false;
}
void SnakePlayer::setHeadSegmentCoords(int x,int y)
{
	list<SnakeSegment *>::iterator it;
	it=segments.begin();
	MyMap::getInstance()->markAsChanged( ( *it )->x, ( *it )->y);
	
	(*it)->x = x;
	(*it)->y = y;
	MyMap::getInstance()->markAsChanged(x,y);
}
void SnakePlayer::backRevisionNum(int number_of_revisions)
{
	list<SnakeSegment *>::iterator it;
	it=segments.begin();
	int i = 0;
	int max_rev =( segments.size()) -1;

	if (max_rev < number_of_revisions)
	{
		number_of_revisions = max_rev;
	}

	while (it != segments.end())
	{
		if (i < number_of_revisions)
		{
			//deleting head segments and marking as changed -map will refresh there
			MyMap::getInstance()->markAsChanged((*it)->x, (*it)->y);
			MyMap::getInstance()->setMapCharAt(MyMap::empty_field,(*it)->x,(*it)->y);
			segments.erase(it);

		}
		else
		{
			break;
		}

		++i;
		it = segments.begin();
	}

}
